
use bracket_lib::prelude::*;


const SCREEN_WIDTH: i32 = 80;
const SCREEN_HEIGHT:i32 = 50;
const FRAME_DURATION:f32 = 75.0;

// 创建游戏模式枚举
enum GameMode {
    Menu,
    Playing,
    End,
}

// 创建角色,并添加位置属性
struct Player {
    x :i32,
    y: i32,
    velocity: f32,   // 垂直方向的速度
    speed:f32, // 控制游戏速度
}

impl Player {
    fn new (x: i32,y: i32) -> Self {
        Self {
            x:x,
            y:y,
            velocity:0.0,
            speed:1.0,
        }
    }

    // 渲染游戏角色到屏幕
    fn render(&mut self, ctx:&mut BTerm) {
        ctx.set(0, self.y, YELLOW, BLACK, to_cp437('@'));
    }

    // 加速下坠
    fn gravity_and_move(&mut self) {
        if self.velocity < 2.0 {
            self.velocity += 0.5;
        }
        // as i32 把浮点数转换为整型
        self.y += self.velocity as i32;
        // self.x += rate 控制游戏速度
        self.x += self.speed as i32;
        if self.y < 0 {
            self.y = 0;
        } 
    }

    // 煽动翅膀上升
    fn flap(&mut self) {
        // 向上的速度为-2.0
        self.velocity = -2.0;
    }

}

// 游戏添加障碍物
struct Obstacle {
    x: i32,   // 坐标系中的位置
    gap_y: i32,  // 缺口中心位置
    size: i32,  // 缺口长度
}

impl Obstacle {
    fn new(x:i32, score:i32) -> Self {
        let mut random = RandomNumberGenerator::new();
        Obstacle { x:x, gap_y: random.range(10, 40), size: i32::max(2, 20-score)}
    }

    // 渲染障碍物
    fn render(& mut self, ctx:&mut BTerm, player_x:i32) {
        // self.x = self.player.x + SCREEN_WIDTH
        // player_x = self.player.x
        let screen_x = self.x - player_x;
        let half_size = self.size / 2;
        // 绘制障碍物上部分
        for y in 0..self.gap_y - half_size {
            ctx.set(
                screen_x, 
                y,
                RED, 
                BLACK, 
                to_cp437('|'),
            )
        }
        // 绘制障碍物下部分
        for y in self.gap_y + half_size .. SCREEN_HEIGHT {
            ctx.set(
                screen_x, 
                y,
                RED, 
                BLACK, 
                to_cp437('|'),
            )
        }
    }
    // 判断是否撞到墙壁
    fn hit_obsracle(&self, player: &Player) -> bool {
        let half_size = self.size / 2;
        let dose_x_match = player.x == self.x;
        // 上边缘判断
        let player_above_gap = player.y < self.gap_y - half_size;
        // 下边缘判断
        let player_bolow_gap = player.y > self.gap_y + half_size;
        
        dose_x_match && ( player_above_gap || player_bolow_gap)
    }


}

struct State { 
    player:Player,
    frame_time:f32,   // 表示累计若干帧之间的时间,用来控制游戏速度
    mode:GameMode,
    // 添加障碍物
    obstacle: Obstacle,
    score: i32,      // 添加得分
}

impl State {
    // 构造方法
    fn new() -> Self {
        Self {
            player:Player::new(5, 25),
            frame_time:0.0,
            mode:GameMode::Menu,
            // 添加障碍物
            obstacle:Obstacle::new(SCREEN_WIDTH, 0),
            score:0,
        }
    }

    fn main_menu(& mut self, ctx:&mut BTerm) {

        ctx.cls();
        ctx.print_centered(5, "welcome to flappy dragon");
        ctx.print_centered(8, "(P) play game");
        ctx.print_centered(9, "(Q) quit game");

        if let Some(key) = ctx.key {
            match key {
                VirtualKeyCode::P => self.restart(),
                VirtualKeyCode::Q => ctx.quitting = true,
                _ => {}
            }
        }


    }

    fn play(&mut self, ctx:&mut BTerm) {

        ctx.cls_bg(NAVY);
        //  ctx.frame_time_ms: 表示两次tick()函数之间调用的间隔时间,间隔越大,屏幕刷新次数越快,通常每秒可以运行60次甚至更多。
        self.frame_time += ctx.frame_time_ms;
        if self.frame_time > FRAME_DURATION {
            self.frame_time = 0.0;
            self.player.gravity_and_move();
        }

        if let Some(VirtualKeyCode::Space) = ctx.key {
            self.player.flap();
        }

        // x值为固定值0
        self.player.render(ctx);

        ctx.print(0, 0, "Please Space to flap");
        ctx.print(0, 1, &format!("Score: {}", self.score));

        // 障碍物x值越来越小
        self.obstacle.render(ctx, self.player.x);

        // self.player.x是一只增加的
        // println!("player-x:{}",self.player.x);

        // 穿越障碍物
        if self.player.x > self.obstacle.x {
            // 根据score得分控制障碍物前进的速度
            self.score += 1;
            // 每得10分,速度增加0.5
            if self.score % 10 == 0 {
                self.player.speed += 0.5;
            }
            self.obstacle = Obstacle::new(self.player.x + SCREEN_WIDTH, self.score);
        }

        if self.player.y > SCREEN_HEIGHT || self.obstacle.hit_obsracle(&self.player) {

            self.mode = GameMode::End;
        }
    }

    fn dead(&mut self, ctx:&mut BTerm) {
        ctx.cls();
        ctx.print_centered(5, "you are dead");
        ctx.print_centered(8, "(P) play game");
        ctx.print_centered(9, "(Q) quit game");

        if let Some(key) = ctx.key {
            match key {
                VirtualKeyCode::P => self.restart(),
                VirtualKeyCode::Q => ctx.quitting = true,
                _ => {}
            }
        }
    }

    // 重新开始后重置得分和障碍物
    fn restart(&mut self) {
        self.player = Player::new(5, 25);
        self.frame_time = 0.0;
        self.mode = GameMode::Playing;
        // 重新添加障碍物
        self.obstacle = Obstacle::new(SCREEN_WIDTH, 0);
        self.score = 0;
    }
}


fn main() -> BError {

    impl GameState for State {
        fn tick(&mut self, ctx: &mut BTerm) {
            // 根据游戏模式,展示不同的内容
            match self.mode {
                GameMode::Menu => self.main_menu(ctx),
                GameMode::Playing => self.play(ctx),
                GameMode::End => self.dead(ctx),
            }
        }
    }

    let context = BTermBuilder::simple80x50().with_title("Flappy Dragon").build()?;

    main_loop(context, State::new())
    
}
